package cn.com.dingtek.genius.manager.server.web.security;

import cn.com.dingtek.genius.manager.server.support.sam.Authenticator;
import cn.com.dingtek.genius.manager.server.support.sam.SecurityContextHolder;
import cn.com.dingtek.genius.manager.server.support.sam.UnauthenticatedException;
import cn.com.dingtek.genius.manager.server.support.sam.UnenforcerException;
import cn.com.dingtek.genius.manager.server.support.sam.annotation.AssertAuth;
import cn.com.dingtek.genius.manager.server.support.sam.annotation.Logical;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class SecurityInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    private SecurityEnforcer enforcer;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        AssertAuth assertAuth = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), AssertAuth.class);
        if (assertAuth == null) {
            return true;
        }

        if (!Authenticator.isLogin(request)) {
            throw new UnauthenticatedException();
        }

        if (!isPermitted(assertAuth.policies(), assertAuth.logical())) {
            throw new UnenforcerException();
        }

        return true;
    }


    private boolean isPermitted(String[] policies, Logical logical) {
        if (policies == null || policies.length == 0) {
            return true;
        }

        return enforcer.enforce(SecurityContextHolder.getContext().getToken(), policies, logical);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        SecurityContextHolder.clearContext();
    }
}
